
// <copyright file="DynamicStringTrimHelper.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   Trims all the string fields (exposed by public _properties)of an object.
// </summary>

namespace SubhadraSolutions.Sharp.Utils.Reflection
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Reflection.Emit;

    /// <summary>
    /// Trims all the string fields (exposed by public _properties)of an object.
    /// </summary>
    /// <typeparam name="T">
    /// </typeparam>
    public static class DynamicStringTrimHelper<T>
    {
        #region Static Fields

        /// <summary>
        ///     The _method delegate.
        /// </summary>
        private static readonly DynamicMethodDelegate _methodDelegate;

        #endregion Static Fields

        #region Constructors and Finalizers

        /// <summary>
        /// Initializes static members of the <see cref="DynamicStringTrimHelper"/> class.
        ///     Initializes the <see cref="DynamicStringTrimHelper{T}"/> class.
        /// </summary>
        static DynamicStringTrimHelper()
        {
            Type tType = typeof(T);
            MethodInfo trimMethod = typeof(StringHelper).GetMethod("Trim", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(object) }, null);

            var dynamicMethod = new DynamicMethod("DynamicTrim", typeof(void), new[] { tType }, typeof(DynamicStringTrimHelper<T>));
            ILGenerator ilGen = dynamicMethod.GetILGenerator();

            PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
            foreach (PropertyInfo property in properties)
            {
                if (property.PropertyType == typeof(string) && property.CanRead && property.CanWrite)
                {
                    ilGen.Emit(OpCodes.Ldarg_0);

                    ilGen.Emit(OpCodes.Ldarg_0);
                    ilGen.Emit(OpCodes.Callvirt, property.GetGetMethod());

                    ilGen.Emit(OpCodes.Call, trimMethod);

                    ilGen.Emit(OpCodes.Callvirt, property.GetSetMethod());
                }
            }

            ilGen.Emit(OpCodes.Ret);
            _methodDelegate = (DynamicMethodDelegate)dynamicMethod.CreateDelegate(typeof(DynamicMethodDelegate));
        }

        #endregion Constructors and Finalizers

        #region Delegates

        /// <summary>
        ///     Delegate DynamicMethodDelegate.
        /// </summary>
        /// <param name="obj">The object.</param>
        private delegate void DynamicMethodDelegate(T obj);

        #endregion Delegates

        #region Public Methods and Operators

        /// <summary>
        /// Trims the strings.
        /// </summary>
        /// <param name="obj">
        /// The object.
        /// </param>
        public static void TrimStrings(T obj)
        {
            _methodDelegate(obj);
        }

        /// <summary>
        /// Trims all the string fields (exposed by public _properties)of an object/enumerable.
        /// </summary>
        /// <param name="enumerable">
        /// The enumerable.
        /// </param>
        public static void TrimStrings(IEnumerable<T> enumerable)
        {
            foreach (T obj in enumerable)
            {
                TrimStrings(obj);
            }
        }

        #endregion Public Methods and Operators
    }
}
